package com.sang.database;

import java.io.File;
import java.io.FileWriter;
import java.io.UnsupportedEncodingException;

import com.sleepycat.bind.tuple.IntegerBinding;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

public class CiteseerDb {

	private static CiteseerDb myBdb = null;
	private EnvironmentConfig envConfig;
	private Environment env;

	private DatabaseConfig dbConfig;
	private Database vertexDb;
	private Database edgeDb;
	

	private CiteseerDb() {}// prevent others to construct the class object
	
	public static CiteseerDb newInstance(String[] dbName) {// single alone pattern,must using static
		if (myBdb == null) {
			myBdb = new CiteseerDb();
			myBdb.openDb(dbName);
		}
		return myBdb;
	}

	// initialize the environment and database
	public void openDb(String[] dbName) {
		try {
			File file = new File("./db/");
			if (!file.exists())
				file.mkdirs();

			envConfig = new EnvironmentConfig();
			envConfig.setAllowCreate(true);
			env = new Environment(file, envConfig);

			dbConfig = new DatabaseConfig();
			dbConfig.setAllowCreate(true);
			vertexDb = env.openDatabase(null, dbName[0], dbConfig);// use env to open db
			edgeDb = env.openDatabase(null, dbName[1], dbConfig);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// close env and database
	public void closeDb() {
		try {
			// close the database first! and then close the environemnt
			if (vertexDb != null) {
				vertexDb.close();
			}
			
			if(edgeDb != null){
				edgeDb.close();
			}

			if (env != null) {
				env.close();
			}
			
			myBdb = null;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public int insertVertex(int key,String value){
		try {
			DatabaseEntry tkey = new DatabaseEntry();
			IntegerBinding.intToEntry(key, tkey);// change int to entry(object)

			// class String can get bytes-->DatabaseEntry(byte[] data
			DatabaseEntry tvalue = new DatabaseEntry(value.getBytes("UTF-8"));

			// another method to change String into entry(object)
			// StringBinding.stringToEntry(value, tvalue);

			// you have finished changing object to entry,then put to db
			if (OperationStatus.SUCCESS != vertexDb.put(null, tkey, tvalue)) {
				System.out.println("database error:fail to insert data !");
				return -1;
			}

		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return -2;
		}

		return 0;
	}
	
	public int insertEdge(String key,String value){
		try {
			DatabaseEntry tkey = new DatabaseEntry(key.getBytes("UTF-8"));

			// class String can get bytes-->DatabaseEntry(byte[] data
			DatabaseEntry tvalue = new DatabaseEntry(value.getBytes("UTF-8"));

			// another method to change String into entry(object)
			// StringBinding.stringToEntry(value, tvalue);

			// you have finished changing object to entry,then put to db
			if (OperationStatus.SUCCESS != edgeDb.put(null, tkey, tvalue)) {
				System.out.println("database error:fail to insert data !");
				return -1;
			}

		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return -2;
		}
		return 0;
	}
	
	public String readVertex(int key){
		String value = null;
		try {
			DatabaseEntry tkey = new DatabaseEntry();
			IntegerBinding.intToEntry(key, tkey);

			DatabaseEntry tvalue = new DatabaseEntry();

			if (OperationStatus.SUCCESS != vertexDb.get(null, tkey, tvalue,
					LockMode.DEFAULT)) {
				System.out.println("database error:fail to get data records!");
			} else {// get the record and change
				value = new String(tvalue.getData());
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return value;
	}
	
	public String readEdge(String key){
		String value = null;
		try {
			DatabaseEntry tkey = new DatabaseEntry(key.getBytes("UTF-8"));
			DatabaseEntry tvalue = new DatabaseEntry();

			if (OperationStatus.SUCCESS != edgeDb.get(null, tkey, tvalue,
					LockMode.DEFAULT)) {
//				System.out.println("database error:fail to get data records!");
			} else {// get the record and change
				value = new String(tvalue.getData());
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return value;
	}
	
	public  void printDB(FileWriter vfw,FileWriter efw){
		Cursor vCursor = null;
		Cursor eCursor = null;
		DatabaseEntry key = new DatabaseEntry();
		DatabaseEntry value = new DatabaseEntry();
		try{
			//准备输出 vertex 库
			vCursor = vertexDb.openCursor(null, null);
			while(vCursor.getNext(key, value,LockMode.DEFAULT) == OperationStatus.SUCCESS){
				String strKey = "" + IntegerBinding.entryToInt(key);
				String strValue = new String(value.getData(), "UTF-8");
				//去掉description
				int pos = strValue.indexOf("@@description:");
				if(pos != -1){
					int pos2 = strValue.indexOf("@@", pos + 6);
					if(pos2 == -1){
						System.out.println("error data:" + strValue + "\n");
						continue;
					}
					strValue = strValue.substring(0, pos) + strValue.substring(pos2);
				}
				
				//输出到vertex.txt
				vfw.write(strKey+"\t"+strValue+"\n");				
			}
			
			//准备输出 edge库
			eCursor = edgeDb.openCursor(null, null);
			while (eCursor.getNext(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
				String strKey = new String(key.getData(), "UTF-8");
				String strValue = new String(value.getData(), "UTF-8");
				//输出到 edge.txt中
				efw.write(strKey + "\t" + strValue + "\n");
			}			
			
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
				if (vCursor != null) {
					vCursor.close();
				}
				if (eCursor != null) {
					eCursor.close();
				}
		}
	}

	public void printSimpleDB(FileWriter vfw,FileWriter efw){
		Cursor vCursor = null;
		Cursor eCursor = null;
		DatabaseEntry key = new DatabaseEntry();
		DatabaseEntry value = new DatabaseEntry();
		try{
			//准备输出 vertex 库
			vCursor = vertexDb.openCursor(null, null);
			while(vCursor.getNext(key, value,LockMode.DEFAULT) == OperationStatus.SUCCESS){
				String strKey = "" + IntegerBinding.entryToInt(key);
				String strValue = new String(value.getData(), "UTF-8");
				//只获取paper title 和 author name等重要信息
				String[] splits = strValue.split("@@");
				//输出到vertex.txt
				int pos = splits[1].indexOf(":");
				if(pos != -1){
					vfw.write(strKey+"\t"+splits[1].substring(pos+1)+"\n");
				}else{
					System.out.println("error data:" + strValue + "\n");
					continue;
				}								
			}
			
			//准备输出 edge库
			eCursor = edgeDb.openCursor(null, null);
			while (eCursor.getNext(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
				String strKey = new String(key.getData(), "UTF-8");
				String strValue = new String(value.getData(), "UTF-8");
				//输出到 edge.txt中
				efw.write(strKey + "\t" + strValue + "\n");
			}			
			
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
				if (vCursor != null) {
					vCursor.close();
				}
				if (eCursor != null) {
					eCursor.close();
				}
		}
	}
	// insert object
	// object can be considered as key or value!
//	public int insert(int key, ObjectData oData) {
//		try {
//			DatabaseEntry tkey = new DatabaseEntry();
//			IntegerBinding.intToEntry(key, tkey);
//
//			DatabaseEntry tvalue = new DatabaseEntry();
//			ObjectTupleBinding obind = new ObjectTupleBinding();
//			obind.objectToEntry(oData, tvalue);// encapsulate key&value to One
//												// Entry
//
//			if (OperationStatus.SUCCESS != db.put(null, tkey, tvalue)) {
//				System.out.println("database error:fail to insert data");
//				return -1;
//			}
//
//		} catch (Exception e) {
//			e.printStackTrace();
//			return -2;
//		}
//		return 0;
//	}
//
//	// get the object data
//	public ObjectData getRecord(int key, boolean flag) {
//		ObjectData od = null;
//		try {
//			ObjectTupleBinding oBind = new ObjectTupleBinding();
//
//			DatabaseEntry tkey = new DatabaseEntry();
//			IntegerBinding.intToEntry(key, tkey);
//
//			DatabaseEntry tvalue = new DatabaseEntry();
//			if (OperationStatus.SUCCESS == db.get(null, tkey, tvalue,
//					LockMode.DEFAULT)) {
//				od = (ObjectData) oBind.entryToObject(tvalue);
//			}
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		return od;
//	}

}
